﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using VNet.VisiSuite.Common.Logger;

namespace VNet.VisiSuite.VisiBoard.WebServer
{
    class WebServerRequestHandler
    {
        private static string _www_path = null;
        private static Dictionary<string, string> _variables = null;

        public static byte[] requestHandler(HttpListenerRequest request, out string mime_type, out bool cache)
        {

            mime_type = "text/html";
            string response = "";
            byte[] data = null;
            cache = false;

            try
            {
                string raw_url = request.RawUrl.ToLower();
                string method = request.HttpMethod.ToUpper();

                if (method == "POST")
                {
                    if (raw_url.StartsWith("/config"))
                    {
                        var post_data = getRequestPostData(request);
                        string hostname = post_data["hostname"];

                        ProcessStartInfo psi = new ProcessStartInfo();
                        psi.WorkingDirectory = System.Configuration.ConfigurationManager.AppSettings["ScriptsFolder"] + "hostname/";
                        psi.FileName = psi.WorkingDirectory + "change_hostname.sh";
                        psi.UseShellExecute = false;
                        psi.Arguments = hostname;
                        Process.Start(psi);
                        
                        raw_url = "/rebooting.html";
                    }

                }

                if ((raw_url.StartsWith("/api/msg/?") || raw_url.StartsWith("/api/msg?")))
                {
                    string msg = request.QueryString["msg"];
                    mime_type = "text/html";

                    if (msg != null)
                    {
                        VNet.VisiSuite.VisiBoard.BusinessLogic.VisiBox.instance().enqueueMessageFromVisiBox(msg);
                        response = "1";
                    }
                    else
                    {
                        response = "0";
                    }
                    // mime_type = "application/json";
                }
                else
                {
                    var fname = raw_url.Substring(raw_url.LastIndexOf('/')+1);
                    if (raw_url.StartsWith("/diag"))
                        fname = "diag.html";
                    else if (raw_url.StartsWith("/config"))
                        fname = "config.html";
                    else if (raw_url.StartsWith("/api/status"))
                        fname = "status.json";

                    if (string.IsNullOrWhiteSpace(fname))
                        fname = "index.html";
                    data = readFile(fname, out mime_type, out cache);
                }

                if (data == null && string.IsNullOrEmpty(response))
                {
                    mime_type = "text/html";
                    data = System.Text.Encoding.UTF8.GetBytes("404: Not found.");
                }

            }
            catch (Exception ex)
            {
                FileLog.Error("handleRequest() - ", ex);
                response = string.Format("<html><body>{0}</body></html>", ex.Message);
            }

            return data != null ? data : System.Text.Encoding.UTF8.GetBytes(response);

        }

        private static Dictionary<string, string> getRequestPostData(HttpListenerRequest request)
        {
            var post_variables = new Dictionary<string, string>();

            try
            {
                if (request.HasEntityBody)
                {

                    using (System.IO.Stream body = request.InputStream) // here we have data
                    {
                        using (System.IO.StreamReader reader = new System.IO.StreamReader(body, request.ContentEncoding))
                        {
                            string data = reader.ReadToEnd();
                            var pairs = data.Split('&');
                            foreach (string key_value in pairs)
                            {
                                var kv = key_value.Split('=');
                                if (kv.Length == 2)
                                    post_variables.Add(kv[0], kv[1]);
                            }
                        }
                    }
                }

            } 
            catch (Exception ex)
            {

            }

            return post_variables;
        }

        private static byte[] readTextFile(string fname, bool variable_substitute = false)
        {
            byte[] data = null;
            try
            {
                string path = _www_path + fname;

                string txt = File.ReadAllText(path);

                if (variable_substitute)
                    txt = substitueVariables(txt);

                data = System.Text.Encoding.UTF8.GetBytes(txt);
                txt = null;
            }
            catch (Exception ex)
            {
                FileLog.Error("readTextFile() - " + fname + " - ", ex);
            }

            return data;
        }

        private static byte[] readBinaryFile(string fname)
        {
            byte[] data = null;
            try
            {
                string path = _www_path + fname;

                data = File.ReadAllBytes(path);
            }
            catch (Exception ex)
            {
                FileLog.Error("readBinaryFile() - " + fname + " - ", ex);
            }

            return data;

        }

        private static byte[] readFile(string fname, out string mime_type, out bool cache)
        {
            mime_type = "text/html";
            byte[] data = null;
            bool not_found = false;
            cache = false;

            if (string.IsNullOrEmpty(_www_path))
                _www_path = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "www/");

            if (fname.EndsWith(".gif"))
            {
                data = readBinaryFile(fname);
                mime_type = "image/gif";
                cache = true;
            }
            else if (fname.EndsWith(".jpg"))
            {
                data = readBinaryFile(fname);
                mime_type = "image/jpeg";
                cache = true;
            }
            else if (fname.EndsWith(".js"))
            {
                data = readTextFile(fname);
                mime_type = "application/javascript";
                cache = true;
            }
            else if (fname.EndsWith(".html"))
            {
                data = readTextFile(fname, true);
                mime_type = "text/html";
            }
            else if (fname.EndsWith(".json"))
            {
                data = readTextFile(fname, true);
                mime_type = "application/json";
            }
            else
            {
                not_found = true;
            }

            if (data == null || not_found)
            {
                mime_type = "text/html";
                data = System.Text.Encoding.UTF8.GetBytes("404: Not found.");
                cache = false;
            }

            return data;
        }


        private static string substitueVariables(string txt)
        {
            int dbm = 0;
            int quality = SystemInfo.wifiSignalQuality(out dbm);
            string wifi = string.Format("{0}% ({1} {2})", quality, dbm, dbm < 0 ? "dBm" : "");

            if (_variables == null)
            {
                _variables = new Dictionary<string, string>();
                // constants
                _variables.Add("$version", SystemInfo.version());
                _variables.Add("$hostname", SystemInfo.hostname());
                _variables.Add("$ipaddress", SystemInfo.ipAddress());
                _variables.Add("$reboot", SystemInfo.lastReboot().ToString());
                _variables.Add("$cell", SystemInfo.cellName());
            }

            _variables["$online"] = SystemInfo.offline() ? "Offline" : "Online";
            _variables["$wifi"] = wifi;
            _variables["$now"] = DateTime.Now.ToString();

            _variables["$battery"] = SystemInfo.BatteryPercentage();
            _variables["$life"] = SystemInfo.BatteryLife();
            _variables["$charging"] = SystemInfo.BatteryCharging();

            StringBuilder sb = new StringBuilder(txt);
            foreach (var pair in _variables)
            {
                sb.Replace(pair.Key, pair.Value);
            }

            return sb.ToString();
        }

    }
}
